package com.inspur.edp.bef.core.logger;

import com.inspur.edp.bef.core.be.BizEntityCacheManager;
import com.inspur.edp.bef.core.session.BefBizContext;
import com.inspur.edp.bef.core.session.FuncSession;
import com.inspur.edp.bef.core.session.FuncSessionManager;
import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.core.context.BizContextManager;
import io.iec.edp.caf.core.context.FrameworkContext;
import org.yaml.snakeyaml.reader.UnicodeReader;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public  class  BefSessionLoggerTrace implements BefSessionLog {
    private static Boolean isOpenTrace = false;
    private static Boolean isOpenStackTrace = false;
    private static Boolean enableSetRedisInfo = false;
    @Override
    public  String openLoggerTrace() {
        isOpenTrace = true;
        return "已开启befContext跟踪工具";
    }

    @Override
    public String openStackTrace(){
        if(!isOpenTrace){
            return "请先开启befContext程序跟踪工具!";
        }
        isOpenStackTrace = true;
        return "已开启堆栈信息";
    }

    @Override
    public String closeLoggerTrace() {
        isOpenTrace = false;
        isOpenStackTrace = false;
        enableSetRedisInfo = false;
        return "已关闭befContext跟踪工具";
    }

    @Override
    public String closeStackTrace() {
        isOpenStackTrace = false;
        return "已关闭堆栈信息";
    }

    @Override
    public String enableSetRedisInfo() {
        if(!isOpenTrace){
            return "请先开启befContext程序跟踪工具!";
        }
        enableSetRedisInfo = true;
        return "开启redis记录";
    }

    @Override
    public String disEnableSetRedisInfo() {
        enableSetRedisInfo = false;
        return "关闭redis记录";
    }

    public static void setTraceInformation(BefBizContext bizContext, FuncSession funcSession, FrameworkContext frameworkContext){
        if (!isOpenTrace){
            return;
        }
        HashMap<String,Object> sessionTrace= new HashMap<String,Object>(11);
        sessionTrace.put("bizContextID",bizContext.getId());
        sessionTrace.put("userSessionId",CAFContext.current.getSessionId());
        if (CAFContext.current.getCurrentSession()!=null){
            sessionTrace.put("userId",CAFContext.current.getCurrentSession().getUserId());
            sessionTrace.put("userCode", CAFContext.current.getCurrentSession().getUserCode());
            sessionTrace.put("sessionType",CAFContext.current.getCurrentSession().getSessionType().toString());
        }
//            sessionTrace.put("BeId",SpringBeanUtils.getBean(BizEntityCacheManager.class).getBEManager().getBEInfo().getBEID());
        if (frameworkContext!=null){
            sessionTrace.put("functionId",frameworkContext.getFuncId());
            sessionTrace.put("functionCode",frameworkContext.getFuncCode());
        }
        sessionTrace.put("createTime",bizContext.getCreationDate().toString());
        if (isOpenStackTrace){
            sessionTrace.put("traceStack",getStackInformation());
        }
        if (enableSetRedisInfo){
            for (Map.Entry<String, Object> entry : sessionTrace.entrySet()) {
                if (entry.getKey()!=null){
                    bizContext.getItems().put(entry.getKey(),entry.getValue());
                }
            }
        }
        SpringBeanUtils.getBean(BizContextManager.class).update(bizContext);
        funcSession.setSessionTrace(sessionTrace);
    }

    public static void setConfigID (FuncSession funcSession){
        if (!isOpenTrace||funcSession.getSessionTrace()==null){
            return;
        }
        ArrayList<String>configIDs =new ArrayList<>();
        if (funcSession.getSessionItemsStack()!=null&&funcSession.getSessionItemsStack().size()>0){
            configIDs.addAll(funcSession.getSessionItems().keySet());
        }
        if (configIDs.size()>0){
                funcSession.getSessionTrace().put("ConfigID",configIDs);
        }
    }

    public List<Map<String,Object>> getSessionTraceInfo(FilterParam filterParam){
        if (!isOpenTrace){
            return null;
        }
        return getSessionTraceList(filterParam);
    }

//    public ArrayList<Map<String,Object>> getSessionTraceInfoByTime(int minutes){
//        if (!isOpenTrace){
//            return null;
//        }
//        return this.getSessionTraceList(true,minutes);
//    }

    private static ArrayList<Map<String,Object>> getSessionTraceList(FilterParam filterParam){
        ArrayList<Map<String,Object>> sessionTraceList = new ArrayList<>();
        int maxCount =filterParam.getMaxCount();
        ZonedDateTime nowDate = null;
        if (filterParam.getMinutes()!=0){
            nowDate = ZonedDateTime.now().minusMinutes(filterParam.getMinutes());
        }
        ConcurrentHashMap<String, ConcurrentHashMap<String, FuncSession>> sessionSets = FuncSessionManager.getCurrent().getBuckets();
        for (ConcurrentHashMap<String, FuncSession> funcSessionMap : sessionSets.values()) {
            if (funcSessionMap!=null&&funcSessionMap.size()!=0){
                for (FuncSession funcSession : funcSessionMap.values()) {
                    Map<String,Object> sessionTrace = funcSession.getSessionTrace();
                    if (sessionTrace!=null && sessionTrace.size()>0){
                        if ((maxCount>0 && sessionTraceList.size() >= maxCount)||sessionTraceList.size()>=50000){
                            break;
                        }
                        if (nowDate != null){
                            ZonedDateTime createTime = ZonedDateTime.parse(sessionTrace.get("createTime").toString(), DateTimeFormatter.ISO_ZONED_DATE_TIME);
                            if (nowDate.compareTo(createTime) <0){
                                continue;
                            }
                        }
                        sessionTraceList.add(sessionTrace);
                    }
                }
            }
        }
        String filePath = filterParam.getFilePath();
        ArrayList<Map<String,Object>> infoList =new ArrayList<>(1);
        HashMap<String,Object> info= new HashMap<String,Object>(1);
        if (filePath!=null && !"".equals(filePath)){
            outPutFile(filterParam.getFilePath(),sessionTraceList);
            info.put("日志信息已保存至目录",filePath);
            infoList.add(info);
            return infoList;
        }
        if(sessionTraceList.size()>0){
            return sessionTraceList;
        }
        if (!isOpenTrace){
            info.put("没有获取到跟踪信息，请先打开程序跟踪器","");
        }else {
            info.put("没有获取到跟踪信息，请稍后再试","");
        }
       infoList.add(info);
        return infoList;
    }

    private static String getStackInformation(){
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        StringBuilder stackInformation = new StringBuilder();
        for (StackTraceElement stackTraceElement : stackTraceElements) {
            stackInformation.append(stackTraceElement.toString()).append("\r\n");
        }
        return stackInformation.toString();
    }

    private static void outPutFile(String filePath,ArrayList<Map<String,Object>> sessionTraceList){
        File file =new File(filePath);
        try {
        if (!file.exists()){
                file.createNewFile();
        }
        BufferedWriter bw = new BufferedWriter(new FileWriter(file));
            for (Map<String, Object> stringObjectMap : sessionTraceList) {
                bw.write("{");
                for (String s : stringObjectMap.keySet()) {
                    bw.write(s+": ");
                    if (stringObjectMap.get(s)==null){
                        bw.write("null");
                    }else bw.write(stringObjectMap.get(s).toString());
                    bw.write("\r\n");
                }
                bw.write("}");
                bw.write("\r\n");
                bw.newLine();
            }
           bw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }








}
